package org.dromara.patrol.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.enums.NoticeMessageType;
import org.dromara.common.core.enums.patrol.ExpiredStatus;
import org.dromara.common.core.enums.patrol.MainTaskType;
import org.dromara.common.core.enums.patrol.RepeatType;
import org.dromara.common.core.enums.patrol.TaskFinishStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.exception.patrol.PatrolException;
import org.dromara.common.core.exception.patrol.TaskException;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.patrol.api.domain.bo.RemotePatrolSubtaskBo;
import org.dromara.patrol.domain.PatrolSubtaskCommon;
import org.dromara.patrol.domain.PatrolTask;
import org.dromara.patrol.domain.bo.PatrolSubtaskCommonBo;
import org.dromara.patrol.domain.bo.PatrolTaskBo;
import org.dromara.patrol.domain.bo.PatrolTaskQuery;
import org.dromara.patrol.domain.model.ExecuteRule;
import org.dromara.patrol.domain.model.Executors;
import org.dromara.patrol.domain.model.PatrolExecutors;
import org.dromara.patrol.domain.vo.PatrolSubtaskCommonVo;
import org.dromara.patrol.domain.vo.PatrolTemplateVo;
import org.dromara.patrol.mapper.PatrolSubtaskCommonMapper;
import org.dromara.patrol.mapper.PatrolTaskMapper;
import org.dromara.patrol.service.IPatrolSubtaskCommonService;
import org.dromara.patrol.service.IPatrolTemplateService;
import org.dromara.system.api.RemoteMessageService;
import org.dromara.system.api.RemoteStoreService;
import org.dromara.system.api.RemoteUserService;
import org.dromara.system.api.domain.bo.RemoteMessageBo;
import org.springframework.stereotype.Service;
import tech.powerjob.client.PowerJobClient;
import tech.powerjob.common.model.LifeCycle;
import tech.powerjob.common.request.http.SaveJobInfoRequest;
import tech.powerjob.common.response.ResultDTO;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static tech.powerjob.common.enums.ExecuteType.STANDALONE;
import static tech.powerjob.common.enums.ProcessorType.BUILT_IN;
import static tech.powerjob.common.enums.TimeExpressionType.CRON;

/**
 * 巡店管理-普通巡店子任务Service业务层处理
 *
 * @author Chan
 * @date 2024-03-21
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class PatrolSubtaskCommonServiceImpl implements IPatrolSubtaskCommonService {

    private final PatrolSubtaskCommonMapper baseMapper;

    private final PatrolTaskMapper patrolTaskMapper;

    private final PowerJobClient powerJobClient;

    private final IPatrolTemplateService patrolTemplateService;
    @DubboReference
    private RemoteUserService remoteUserService;

    @DubboReference
    private RemoteStoreService remoteStoreService;

    @DubboReference
    private RemoteMessageService remoteMessageService;
    /**
     * 查询巡店管理-普通巡店子任务
     */
    @Override
    public PatrolSubtaskCommonVo queryById(Long id){
        // TODO 优化异步多线程处理，或者全局 REDIS 缓存
        PatrolSubtaskCommon vo = baseMapper.selectById(id);
        if (vo == null) {
            return new PatrolSubtaskCommonVo();
        }
        // 通过门店id，门店ids查询门店名称
        List<Long> storeIds = CollUtil.newArrayList(vo.getStoreId());
        // 不能用 stream 相关
        if (CollUtil.isNotEmpty(vo.getStoreIds())) {
            for (Object storeId : vo.getStoreIds()) {
                storeIds.add(Convert.toLong(storeId));
            }
        }
        Map<Long, String> storeNameMap = remoteStoreService.selectNamesByStoreList(storeIds);

        // 通过userId、executor查询用户名称
        List<Long> userIds = CollUtil.newArrayList(vo.getUserId(),
            vo.getExecutor(),
            vo.getCreator());
        // 不能用 stream 相关
        if (CollUtil.isNotEmpty(vo.getNotifierIds())) {
            for (Object notifierId : vo.getNotifierIds()) {
                userIds.add(Convert.toLong(notifierId));
            }
        }
        Map<Long, String> userNameMap = remoteUserService.selectNickNameByIds(userIds);
        userNameMap.putAll(storeNameMap);
        // 通过templateId查询模板名称、模板模式
        PatrolTemplateVo patrolTemplateVo = patrolTemplateService.queryById(vo.getTemplateId());
        Map<Long, String> templateNameMap = new HashMap<>(patrolTemplateVo != null
            ? Map.of(vo.getTemplateId(), patrolTemplateVo.getName())
            : new HashMap<>());
        PatrolSubtaskCommonVo result = BeanUtil.copyProperties(vo, PatrolSubtaskCommonVo.class);
        if (ObjUtil.isNull(result)) {
            return new PatrolSubtaskCommonVo();
        }
        result.setMarkStrategy(patrolTemplateVo != null ? patrolTemplateVo.getMarkStrategy() : null);
        userNameMap.putAll(templateNameMap);
        result.setNameMap(userNameMap);
        return result;
    }

    /**
     * 查询主任务巡店管理-普通巡店子任务
     * @param taskId
     * @return
     */
    @Override
    public PatrolSubtaskCommon queryMainTask(Long taskId) {
        return baseMapper.selectOne(new LambdaQueryWrapper<PatrolSubtaskCommon>()
            .eq(PatrolSubtaskCommon::getTaskId, taskId)
            .eq(PatrolSubtaskCommon::getMainTask, MainTaskType.MAIN.getCode()), false);
    }

    /**
     * 查询巡店管理-普通巡店子任务(主任务、非主任务)列表
     */
    @Override
    public TableDataInfo<PatrolSubtaskCommonVo> queryPageList(PatrolTaskQuery patrolTaskQuery) {
        LambdaQueryWrapper<PatrolSubtaskCommon> lqw = buildQueryWrapper(patrolTaskQuery);
        Page<PatrolSubtaskCommon> result = baseMapper.selectPage(patrolTaskQuery.build(), lqw);
        Page<PatrolSubtaskCommonVo> retPage = BeanUtil.copyProperties(result, Page.class);
        if (ObjUtil.isNull(result) || CollUtil.isEmpty(result.getRecords())) {
            return TableDataInfo.build(retPage);
        }
        List<PatrolSubtaskCommon> tempList = result.getRecords();
        // TODO 优化异步多线程处理 或者 做成全局 REDIS 缓存
        // 通过门店id，门店ids查询门店名称
        List<Long> storeIds = tempList
            .stream()
            .flatMap(vo -> Stream.concat(
                // 将 vo.getStoreId() 返回的 Integer 转换为 Long
                vo.getStoreId() != null ? Stream.of(Convert.toLong(vo.getStoreId())) : Stream.empty(),
                // 假设 vo.getStoreIds() 返回的是 Long 类型的集合
                CollUtil.isEmpty(vo.getStoreIds()) ? Stream.empty() : vo.getStoreIds().stream()
            ))
            .distinct()
            .collect(Collectors.toList()); // 不需要显式指定类型参数
        Map<Long, String> storeNameMap = remoteStoreService.selectNamesByStoreList(storeIds);
        // 通过userId、executor查询用户名称
        List<Long> executorIds = Lists.newArrayList();
        tempList.forEach(item -> {
            List<PatrolExecutors> patrolExecutorsList = JsonUtils.parseArray(JsonUtils
                .toJsonString(item.getPatrolExecutors()), PatrolExecutors.class);
            if (CollUtil.isNotEmpty(patrolExecutorsList)) {
                patrolExecutorsList.forEach(executors -> {
                    List<Executors> executorsList = JsonUtils.parseArray(JsonUtils
                        .toJsonString(executors.getExecutors()), Executors.class);
                    if (CollUtil.isNotEmpty(executorsList)) {
                        executorsList.forEach(executor -> {
                            if (ObjUtil.isNotNull(executor) && ObjUtil.isNotNull(executor.getExecutor())) {
                                executorIds.add(Convert.toLong(executor.getExecutor()));
                            }
                        });
                    }
                });
            }
        });
        List<Long> userIds = Stream
            .concat(tempList.stream()
                .map(PatrolSubtaskCommon::getExecutor),
                Stream.concat(tempList.stream().map(PatrolSubtaskCommon::getCreator), executorIds.stream()))
            .filter(Objects::nonNull)
            .distinct()
            .toList();
        Map<Long, String> userNameMap = remoteUserService.selectNickNameByIds(userIds);
        // 通过templateId查询模板名称、模板模式
        List<PatrolTemplateVo> patrolTemplateVos = patrolTemplateService.queryByIds(tempList
            .stream()
            .map(PatrolSubtaskCommon::getTemplateId)
            .distinct()
            .collect(Collectors.toList()));
        Map<Long, PatrolTemplateVo> templateNameMap = new HashMap<>();
        if (CollUtil.isNotEmpty(patrolTemplateVos)) {
            templateNameMap = patrolTemplateVos.stream()
                .collect(Collectors
                    .toMap(PatrolTemplateVo::getTemplateId, Function.identity()));
        }

        Map<Long, PatrolTemplateVo> finalTemplateNameMap = templateNameMap;
        List<PatrolSubtaskCommonVo> ret = BeanUtil.copyToList(tempList, PatrolSubtaskCommonVo.class);
        Objects.requireNonNull(ret).forEach(item -> {
            if (CollUtil.isNotEmpty(item.getPatrolExecutors())) {
                item.getPatrolExecutors().forEach(executors -> {
                    if (ObjUtil.isNotNull(executors))
                        executors.getExecutors()
                            .forEach(executor -> {
                                if (ObjUtil.isNotNull(executor) && ObjUtil.isNotNull(executor.getExecutor()))
                                    executor.setExecutorName(userNameMap.computeIfAbsent(executor.getExecutor(), key -> null));
                            });
                });
            }

            if (CollUtil.isNotEmpty(item.getStoreIds())) {
                item.getStoreIds().forEach(storeId -> {
                    if (ObjUtil.isNotNull(storeId)) {
                        Long tempId = Convert.toLong(storeId);
                        item.getNameMap().put(tempId, storeNameMap.computeIfAbsent(tempId, key -> null));
                    }
                });
            }
            if (ObjUtil.isNotNull(item.getTemplateId())) {
                Long templateId = Convert.toLong(item.getTemplateId());
                PatrolTemplateVo patrolTemplateVo = finalTemplateNameMap.computeIfAbsent(templateId, key -> new PatrolTemplateVo());
                item.getNameMap().put(templateId, patrolTemplateVo.getName());
                item.setMarkStrategy(patrolTemplateVo.getMarkStrategy());
            }
            if (ObjUtil.isNotNull(item.getCreator())) {
                Long creator = Convert.toLong(item.getCreator());
                item.getNameMap().put(creator, userNameMap.computeIfAbsent(creator, key -> null));
            }
            if (ObjUtil.isNotNull(item.getUserId())) {
                Long userId = Convert.toLong(item.getUserId());
                item.getNameMap().put(userId,  userNameMap.computeIfAbsent(userId, key -> null));
            }
            if (ObjUtil.isNotNull(item.getExecutor())) {
                Long executor = Convert.toLong(item.getExecutor());
                item.getNameMap().put(executor, userNameMap.computeIfAbsent(executor, key -> null));
            }
            if (ObjUtil.isNotNull(item.getStoreId())) {
                Long storeId = Convert.toLong(item.getStoreId());
                item.getNameMap().put(storeId, storeNameMap.computeIfAbsent(storeId, key -> null));
            }
        });
        retPage.setRecords(ret);
        return TableDataInfo.build(retPage);
    }

    /**
     * 查询巡店管理-普通巡店子任务列表
     */
    @Override
    public List<PatrolSubtaskCommonVo> queryList(PatrolSubtaskCommonBo bo) {
        LambdaQueryWrapper<PatrolSubtaskCommon> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    /**
     * 查询巡店管理-普通巡店子任务列表
     * @param ids
     * @return
     */
    @Override
    public List<PatrolSubtaskCommon> queryList(List<Long> ids) {
        return baseMapper.selectList(new LambdaQueryWrapper<PatrolSubtaskCommon>()
            .in(PatrolSubtaskCommon::getId, ids));
    }

    /**
     * 查询巡店管理-普通巡店子任务列表
     * @param patrolTaskQuery
     * @return
     */
    private LambdaQueryWrapper<PatrolSubtaskCommon> buildQueryWrapper(PatrolTaskQuery patrolTaskQuery) {
        LambdaQueryWrapper<PatrolSubtaskCommon> lqw = Wrappers.lambdaQuery();
        // 时间查询
        lqw.ge(ObjUtil.isNotNull(patrolTaskQuery.getTaskCreatedStartTime()),
            PatrolSubtaskCommon::getTaskCreatedTime, patrolTaskQuery.getTaskCreatedStartTime());
        lqw.le(ObjUtil.isNotNull(patrolTaskQuery.getTaskCreatedEndTime()),
            PatrolSubtaskCommon::getTaskCreatedTime, patrolTaskQuery.getTaskCreatedEndTime());

        // 任务名称、关键字人员相关
        if (StringUtils.isNotBlank(patrolTaskQuery.getKeyword())) {
            List<Long> userIds;
            userIds = remoteUserService.selectUserIdsLikeNickName(patrolTaskQuery.getKeyword());
            StringJoiner joiner = new StringJoiner(" OR ");
            // 匹配patrol_executors  executor字段
            userIds.forEach(item -> joiner.add("JSON_CONTAINS(patrol_executors, JSON_OBJECT('executors', JSON_ARRAY(JSON_OBJECT('executor', " + item + "))))"));
            String userStr = StringUtils.join(userIds,",");
            String joinerStr = joiner.toString();
            // 关键字 创建人
            lqw.like(StringUtils.isNotBlank(patrolTaskQuery.getKeyword()), PatrolSubtaskCommon::getName, patrolTaskQuery.getKeyword());
            lqw.and(StringUtils.isNotBlank(userStr) || StringUtils.isNotBlank(joinerStr), wrapper -> wrapper
                    .or(StringUtils.isNotBlank(userStr))
                    .apply(StringUtils.isNotBlank(userStr), "FIND_IN_SET(creator, {0})", userStr)
                    .or(StringUtils.isNotBlank(userStr))
                    .apply(StringUtils.isNotBlank(userStr),"FIND_IN_SET(executor, {0})", userStr)
                    .or(StringUtils.isNotBlank(joinerStr))
                    .apply(StringUtils.isNotBlank(joinerStr), joinerStr));
        }
        //  任务状态查询
        lqw.in(CollUtil.isNotEmpty(patrolTaskQuery.getStatus()),
            PatrolSubtaskCommon::getStatus, patrolTaskQuery.getStatus());
        //  门店查询
        if (ArrayUtil.isNotEmpty(patrolTaskQuery.getStoreIds())) {
            StringJoiner joiner = new StringJoiner(" OR ");
            Arrays.stream(patrolTaskQuery.getStoreIds())
                .mapToObj(item -> "JSON_CONTAINS(store_ids, CAST(" + item + " AS JSON))")
                .forEach(joiner::add);
            String conditions = joiner.toString();
            lqw.and(true, wrapper -> wrapper
                .apply("FIND_IN_SET(store_id, {0})", Arrays.stream(patrolTaskQuery.getStoreIds())
                        .mapToObj(String::valueOf) // 将 long 转换为 String
                        .collect(Collectors.joining(",")))
                .or(StringUtils.isNotEmpty(conditions))
                .apply(StringUtils.isNotEmpty(conditions), conditions));
        }
        //  对象查询
        switch (patrolTaskQuery.getTaskObject()) {
            case ALL -> {
                // 不是超管
                if (!LoginHelper.isTenantAdmin()
                    && !LoginHelper.isSuperAdmin()) {
                    lqw.and(true, wrapper -> wrapper.eq(PatrolSubtaskCommon::getUserId, LoginHelper.getUserId())
                        .eq(PatrolSubtaskCommon::getMainTask, MainTaskType.NON_MAIN.getCode())
                        .or()
                        .eq(PatrolSubtaskCommon::getCreator, LoginHelper.getUserId())
                        .eq(PatrolSubtaskCommon::getMainTask, MainTaskType.MAIN.getCode()));
                }
            }
            case OWN_RECEIVE -> lqw.eq(PatrolSubtaskCommon::getUserId, LoginHelper.getUserId())
                .eq(PatrolSubtaskCommon::getMainTask, MainTaskType.NON_MAIN.getCode());
            case OWN_PUBLISH -> lqw.eq(PatrolSubtaskCommon::getCreator, LoginHelper.getUserId())
                .eq(PatrolSubtaskCommon::getMainTask, MainTaskType.MAIN.getCode());
            default -> {
            }
        }
        //  按照时间，任务状态倒序
        lqw.orderBy(true, false, PatrolSubtaskCommon::getTaskCreatedTime, PatrolSubtaskCommon::getStatus);
        return lqw;
    }

    private LambdaQueryWrapper<PatrolSubtaskCommon> buildQueryWrapper(PatrolSubtaskCommonBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<PatrolSubtaskCommon> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getName()), PatrolSubtaskCommon::getName, bo.getName());
        lqw.eq(bo.getUserId() != null, PatrolSubtaskCommon::getUserId, bo.getUserId());
        lqw.eq(bo.getTaskId() != null, PatrolSubtaskCommon::getTaskId, bo.getTaskId());
        lqw.eq(bo.getStartTime() != null, PatrolSubtaskCommon::getStartTime, bo.getStartTime());
        lqw.eq(bo.getFinishTime() != null, PatrolSubtaskCommon::getFinishTime, bo.getFinishTime());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), PatrolSubtaskCommon::getStatus, bo.getStatus());
        lqw.eq(StringUtils.isNotBlank(bo.getExecutor()), PatrolSubtaskCommon::getExecutor, bo.getExecutor());
        lqw.eq(StringUtils.isNotBlank(bo.getCycleTaskId()), PatrolSubtaskCommon::getCycleTaskId, bo.getCycleTaskId());
        lqw.eq(StringUtils.isNotBlank(bo.getCycleType()), PatrolSubtaskCommon::getCycleType, bo.getCycleType());
        lqw.eq(bo.getStoreId() != null, PatrolSubtaskCommon::getStoreId, bo.getStoreId());
//        lqw.eq(StringUtils.isNotBlank(bo.getStoreIds()), PatrolSubtaskCommon::getStoreIds, bo.getStoreIds());
        lqw.eq(StringUtils.isNotBlank(bo.getExecuteDateStart()), PatrolSubtaskCommon::getExecuteDateStart, bo.getExecuteDateStart());
        lqw.eq(StringUtils.isNotBlank(bo.getExecuteDateEnd()), PatrolSubtaskCommon::getExecuteDateEnd, bo.getExecuteDateEnd());
        lqw.eq(StringUtils.isNotBlank(bo.getExecuteTimeStart()), PatrolSubtaskCommon::getExecuteTimeStart, bo.getExecuteTimeStart());
        lqw.eq(StringUtils.isNotBlank(bo.getExecuteTimeEnd()), PatrolSubtaskCommon::getExecuteTimeEnd, bo.getExecuteTimeEnd());
        lqw.eq(StringUtils.isNotBlank(bo.getTemplateRule()), PatrolSubtaskCommon::getTemplateRule, bo.getTemplateRule());
        lqw.eq(bo.getTemplateId() != null, PatrolSubtaskCommon::getTemplateId, bo.getTemplateId());
        //lqw.eq(StringUtils.isNotBlank(bo.getNotifierIds()), PatrolSubtaskCommon::getNotifierIds, bo.getNotifierIds());
        lqw.eq(StringUtils.isNotBlank(bo.getMainTask()), PatrolSubtaskCommon::getMainTask, bo.getMainTask());
        lqw.eq(bo.getTaskCreatedTime() != null, PatrolSubtaskCommon::getTaskCreatedTime, bo.getTaskCreatedTime());
        lqw.eq(StringUtils.isNotBlank(bo.getTaskSubType()), PatrolSubtaskCommon::getTaskSubType, bo.getTaskSubType());
        lqw.eq(StringUtils.isNotBlank(bo.getVer()), PatrolSubtaskCommon::getVer, bo.getVer());
        lqw.eq(bo.getVideoStartTime() != null, PatrolSubtaskCommon::getVideoStartTime, bo.getVideoStartTime());
        lqw.eq(bo.getVideoEndTime() != null, PatrolSubtaskCommon::getVideoEndTime, bo.getVideoEndTime());
        // lqw.eq(StringUtils.isNotBlank(bo.getPatrolExecutors()), PatrolSubtaskCommon::getPatrolExecutors, bo.getPatrolExecutors());
        //lqw.eq(StringUtils.isNotBlank(bo.getExecuteRule()), PatrolSubtaskCommon::getExecuteRule, bo.getExecuteRule());
        lqw.eq(bo.getExecuteEndTime() != null, PatrolSubtaskCommon::getExecuteEndTime, bo.getExecuteEndTime());
        lqw.eq(bo.getExecuteStartTime() != null, PatrolSubtaskCommon::getExecuteStartTime, bo.getExecuteStartTime());
        lqw.eq(StringUtils.isNotBlank(bo.getExpiredStatus()), PatrolSubtaskCommon::getExpiredStatus, bo.getExpiredStatus());
        return lqw;
    }

    /**
     * 新增巡店管理-普通巡店子任务
     * @param patrolSubtaskCommon
     * @return
     */
    @Override
    public Long insert(PatrolSubtaskCommon patrolSubtaskCommon) {
        boolean flag = baseMapper.insert(patrolSubtaskCommon) > 0;
        if (flag) {
            return patrolSubtaskCommon.getId();
        } else {
            throw new TaskException("新增实时巡店任务失败");
        }
    }

    /**
     * 新增巡店管理-普通巡店子任务
     */
    @Override
    public Boolean insertByBo(PatrolSubtaskCommonBo bo) {
        PatrolSubtaskCommon add = MapstructUtils.convert(bo, PatrolSubtaskCommon.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改巡店管理-普通巡店子任务
     */
    @Override
    @GlobalTransactional
    public Boolean updateByBo(PatrolTaskBo bo, Long subtaskId) {
        PatrolSubtaskCommon oldPatrolSubtaskCommon = baseMapper.selectById(subtaskId);
        if (ObjUtil.isNull(oldPatrolSubtaskCommon)
            || !MainTaskType.MAIN.getCode().equals(oldPatrolSubtaskCommon.getMainTask())) {
            throw new PatrolException("任务不存在");
        }
        // 通过 taskId 查找 patrol_task 数据
        PatrolTask oldPatrolTask = patrolTaskMapper.selectById(oldPatrolSubtaskCommon.getTaskId());

        // 判断是否是租户管理员，是的话，可编辑所有主任务，否的话只能编辑自己发布的主任务, 判断任务是否进行中，进行中不能编辑、修改
        if (!LoginHelper.isSuperAdmin()
            && !LoginHelper.isTenantAdmin()
            && !Objects.equals(LoginHelper.getUserId(), oldPatrolSubtaskCommon.getCreator())) {
            throw new ServiceException("权限异常无法修改", HttpStatus.UNAUTHORIZED);
        }

        if (!TaskFinishStatus.TODO.getCode().equals(oldPatrolSubtaskCommon.getStatus())
            || ObjUtil.isNull(oldPatrolTask)) {
            throw new ServiceException("任务状态异常", HttpStatus.MOVED_PERM);
        }
        //发生消息通知
        sendMessage(bo);
        // 删除原子任务、定时任务
        if(deleteLogic(oldPatrolSubtaskCommon, oldPatrolTask)) {
            bo.setTaskId(oldPatrolTask.getTaskId());
            // 创建定时任务，用于检查子任务是否在规定时间内完成，刷新子主任务过期状态
            ResultDTO<Long> result = powerJobClient.saveJob(getMainTaskJobInfoRequest(bo));
            if (result.isSuccess()) {
                log.info("insertLogic===>创建主任务过期状态定时任务成功，任务ID={}", result.getData());
                // 添加新子任务，修改 patrol_task 老数据
                return insertLogic(bo, oldPatrolTask);
            }
        }
        throw new ServiceException("任务状态异常", HttpStatus.MOVED_PERM);
    }

    private void sendMessage(PatrolTaskBo bo) {
        // 执行人
        List<PatrolExecutors> patrolExecutors = bo.getPatrolExecutors();
        if (CollUtil.isEmpty(patrolExecutors)) {
            return;
        }
        List<RemoteMessageBo> handlerMessageList = new ArrayList<>();
        for (PatrolExecutors patrolExecutor : patrolExecutors) {
            //门店
            List<Executors> executors = patrolExecutor.getExecutors();
            for (Executors executor : executors) {
                //门店下面需要处理的人
                handlerMessageList.add(createRemoteMessageBo(executor, patrolExecutor));
            }
        }
        //根据接收人id,转化成map集合
        Map<Long, List<RemoteMessageBo>> map = handlerMessageList.stream().
                collect(Collectors.groupingBy(RemoteMessageBo::getRecordId));
        handlerMessageList.clear();
        map.forEach((k, v) -> {
            RemoteMessageBo remoteMessageBo = new RemoteMessageBo();
            remoteMessageBo.setType(NoticeMessageType.NOTICE_RECEIVE_TASK);
            remoteMessageBo.setMessageContent( NoticeMessageType.NOTICE_RECEIVE_TASK.getAlert().formatted(v.size()));
            remoteMessageBo.setTitle(NoticeMessageType.NOTICE_RECEIVE_TASK.getTitle());
            remoteMessageBo.setStatus("0");
            remoteMessageBo.setSendId(LoginHelper.getUserId());
            remoteMessageBo.setRecordId(k);
            remoteMessageBo.setUrl("/inspectionManagement/task/taskList");
            handlerMessageList.add(remoteMessageBo);
        });
        remoteMessageService.insertBatchByBo(handlerMessageList);
    }

    private SaveJobInfoRequest getMainTaskJobInfoRequest(PatrolTaskBo bo) {
        SaveJobInfoRequest request = new SaveJobInfoRequest();
        request.setMinCpuCores(0);
        request.setMinDiskSpace(0);
        request.setMinMemorySpace(0);
        request.setJobName(bo.getName() + "_主任务过期状态刷新");
        request.setJobParams(bo.getTaskId() + "");
        request.setExecuteType(STANDALONE);
        request.setTimeExpressionType(CRON);
        request.setTimeExpression(StringUtils.convertTimeStrToCron(bo.getExecuteRule().getExecuteDateEnd()
            + " " + bo.getExecuteRule().getExecuteTimeEnd()));
        LifeCycle lifeCycle = new LifeCycle();
        lifeCycle.setStart(bo.getExpectStartTime());
        lifeCycle.setEnd(bo.getExpectFinishTime());
        request.setLifeCycle(lifeCycle);
        request.setProcessorType(BUILT_IN);
        request.setConcurrency(Integer.MAX_VALUE);
        request.setProcessorInfo("org.dromara.job.processors.PatrolTaskCheckMainExpiredProcessor");
        return request;
    }

    /**
     * 删除巡店管理-删除原子任务、定时任务
     * @param patrolSubtaskCommon
     * @param oldPatrolTask
     * @return
     */
    private Boolean deleteLogic(PatrolSubtaskCommon patrolSubtaskCommon, PatrolTask oldPatrolTask) {
        // 通过taskId，获取所有定时任务id
        List<Long> cycleTaskIds = baseMapper.selectObjs(new LambdaQueryWrapper<PatrolSubtaskCommon>()
            .eq(PatrolSubtaskCommon::getTaskId, patrolSubtaskCommon.getTaskId())
            .select(PatrolSubtaskCommon::getCycleTaskId));
        // 删除所有 taskId 的子任务、定时任务
        boolean flag = true;
        if (ObjUtil.isNotNull(oldPatrolTask)
            && ObjUtil.isNotNull(oldPatrolTask.getCycleTaskId())) {
            ResultDTO<Void> result = powerJobClient.deleteJob(oldPatrolTask.getCycleTaskId());
            flag = result.isSuccess();
        }

        if (flag && baseMapper.delete(new LambdaQueryWrapper<PatrolSubtaskCommon>()
            .eq(PatrolSubtaskCommon::getTaskId, patrolSubtaskCommon.getTaskId())) > 0){
            cycleTaskIds.stream().filter(Objects::nonNull).forEach(powerJobClient::deleteJob);
            return true;
        }
        throw new TaskException("删除子任务失败");
    }

    private Boolean insertLogic(PatrolTaskBo bo, PatrolTask add) {
        PatrolSubtaskCommon patrolSubtaskCommon = buildPatrolSubtaskCommon(bo);
        // 新增子任务（主）
        if (insert(patrolSubtaskCommon) > 0) {
            // 更新 patrol_task 任务数据,判断当前任务结束时间，如果小于当前时间，则只创建主子任务，不创建非子任务、定时任务
            if (updatePatrolTask(patrolSubtaskCommon, add)
                && patrolSubtaskCommon.getExecuteEndTime() >= System.currentTimeMillis() + 5000) {
                // 创建定时任务,用于循环周期内非子任务的创建
                ResultDTO<Long> result = powerJobClient.saveJob(getSaveJobInfoRequest(bo));
                if (result.isSuccess()) {
                    if (powerJobClient.runJob(result.getData()).isSuccess()) {
                        return true;
                    } else {
                        // 删除已经创建的定时任务
                        powerJobClient.deleteJob(result.getData());
                    }
                }
            } else {
                return true;
            }
        }
        throw new TaskException("新增实时巡店主任务失败");
    }

    private void convert(PatrolTaskBo bo) {
        bo.setTenantId(LoginHelper.getTenantId());
        bo.setCreatedTime(System.currentTimeMillis());
        bo.setExpectStartTime(getExpectStartTime(bo.getExecuteRule()));
        bo.setExpectFinishTime(getExpectFinishTime(bo.getExecuteRule()));
        bo.setCycleType(getCycleType(bo.getExecuteRule()));
        bo.setCreator(LoginHelper.getUserId());
        bo.setStatus(TaskFinishStatus.TODO);
        bo.setVer("V1");
        bo.setStoreIds(bo.getPatrolExecutors().stream().map(PatrolExecutors::getStoreId).toList());
    }

    /**
     * 获取巡店管理-巡店任务（实时、现场、录像，不包含自检任务）配置周期类型
     * @param executeRule
     * @return
     */
    private RepeatType getCycleType(ExecuteRule executeRule) {
        return executeRule.getCycleType();
    }

    /**
     * 获取巡店管理-巡店任务（实时、现场、录像，不包含自检任务）配置预计开始时间
     * @param executeRule
     * @return
     */
    private Long getExpectStartTime(ExecuteRule executeRule) {
        Date date = DateUtils.parseDate(executeRule.getExecuteDateStart()
            +  " " + executeRule.getExecuteTimeStart());
        return date.getTime();
    }

    /**
     * 获取巡店管理-巡店任务（实时、现场、录像，不包含自检任务）配置预计结束时间
     * @param executeRule
     * @return
     */
    private Long getExpectFinishTime(ExecuteRule executeRule) {
        Date date = DateUtils.parseDate(executeRule.getExecuteDateEnd()
            + " " + executeRule.getExecuteTimeEnd());
        return date.getTime();
    }

    /**
     * 构建pj定时任务request
     * @param bo
     * @return
     */
    private SaveJobInfoRequest getSaveJobInfoRequest(PatrolTaskBo bo) {
        SaveJobInfoRequest request = new SaveJobInfoRequest();
        request.setMinCpuCores(0);
        request.setMinDiskSpace(0);
        request.setMinMemorySpace(0);
        request.setJobName(bo.getName());
        request.setJobParams(bo.getTaskId() + "");
        request.setExecuteType(STANDALONE);
        request.setTimeExpressionType(CRON);
        switch (bo.getCycleType()) {
            case NO_REPEAT ->
                    request.setTimeExpression(StringUtils.convertTimeStrToCron(bo.getExecuteRule().getExecuteDateEnd()
                            + " " + bo.getExecuteRule().getExecuteTimeEnd()));
            case DAILY -> request.setTimeExpression("0 0 0 1/1 * ? *");
            case WEEKLY -> request.setTimeExpression("0 0 0 * * "
                    + CollUtil.join(bo.getExecuteRule().getWeeklyRule(), ",") + " *");
            case MONTHLY -> request.setTimeExpression("0 0 0 "
                    + CollUtil.join(bo.getExecuteRule().getMonthlyRule(), ",") + " * ?");
            default -> {
            }
        }
        LifeCycle lifeCycle = new LifeCycle();
        lifeCycle.setStart(bo.getExpectStartTime());
        lifeCycle.setEnd(bo.getExpectFinishTime());
        request.setLifeCycle(lifeCycle);
        request.setProcessorType(BUILT_IN);
        request.setConcurrency(Integer.MAX_VALUE);
        request.setProcessorInfo("org.dromara.job.processors.PatrolTaskCircleCreateProcessor");
        return request;
    }

    /**
     * 更新巡店任务
     * @param patrolSubtaskCommon
     * @param add
     * @return
     */
    private Boolean updatePatrolTask(PatrolSubtaskCommon patrolSubtaskCommon, PatrolTask add) {
        add.setMainSubtaskId(patrolSubtaskCommon.getId());
        add.setExpectStartTime(patrolSubtaskCommon.getExecuteStartTime());
        add.setExpectFinishTime(patrolSubtaskCommon.getExecuteEndTime());
        add.setCycleType(patrolSubtaskCommon.getCycleType());
        add.setName(patrolSubtaskCommon.getName());
        add.setPatrolExecutors(patrolSubtaskCommon.getPatrolExecutors());
        add.setTemplateId(patrolSubtaskCommon.getTemplateId());
        add.setTemplateRule(patrolSubtaskCommon.getTemplateRule());
        add.setTaskType(patrolSubtaskCommon.getTaskSubType());
        add.setTaskSubType(patrolSubtaskCommon.getTaskSubType());
        return patrolTaskMapper.updateById(add) > 0;
    }

    private PatrolSubtaskCommon buildPatrolSubtaskCommon(PatrolTaskBo bo) {
        convert(bo);
        PatrolSubtaskCommon add = BeanUtil.copyProperties(bo, PatrolSubtaskCommon.class);
        validEntityBeforeSave(add);
        add.setTaskId(bo.getTaskId());
        add.setMainTask(MainTaskType.MAIN.getCode());
        add.setTaskCreatedTime(bo.getCreatedTime());
        add.setTenantId(bo.getTenantId());
        add.setExecuteDateStart(bo.getExecuteRule().getExecuteDateStart());
        add.setExecuteDateEnd(bo.getExecuteRule().getExecuteDateEnd());
        add.setExecuteTimeStart(bo.getExecuteRule().getExecuteTimeStart());
        add.setExecuteTimeEnd(bo.getExecuteRule().getExecuteTimeEnd());
        add.setNotifierIds(bo.getNotifierIds());
        add.setExecuteStartTime(bo.getExpectStartTime());
        add.setExecuteEndTime(bo.getExpectFinishTime());
        add.setExpiredStatus(getExpiredStatus(System.currentTimeMillis(), bo.getExpectFinishTime()));
        return add;
    }

    private String getExpiredStatus(Long currentTime, Long finishTime) {
        return DateUtils.getTaskExpiredStatusByTime(currentTime, finishTime, 1000 * 60 * 60 * 24L);
    }

    @Override
    public Boolean updateById(PatrolSubtaskCommon patrolSubtaskCommon) {
        return baseMapper.updateById(patrolSubtaskCommon) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(PatrolSubtaskCommon entity){
        if (ObjUtil.isNull(entity)) {
            throw new PatrolException("保存失败，任务信息为空");
        }
    }

    /**
     * 批量删除巡店管理-普通巡店子任务
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){

        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 批量新增巡店管理-普通巡店子任务
     * @param list
     * @return
     */
    @Override
    public Boolean saveBatch(List<PatrolSubtaskCommon> list) {
        return baseMapper.insertBatch(list);
    }

    /**
     * 根据cycleTaskId查询子任务数量
     * @param remotePatrolSubtaskBo
     * @return
     */
    @Override
    public Long countByRemoteBo(RemotePatrolSubtaskBo remotePatrolSubtaskBo) {
        return baseMapper.selectCount(new LambdaQueryWrapper<PatrolSubtaskCommon>()
                .eq(PatrolSubtaskCommon::getExecuteDateEnd, remotePatrolSubtaskBo.getDateStr())
                .eq(PatrolSubtaskCommon::getTaskId, remotePatrolSubtaskBo.getTaskId())
                .eq(PatrolSubtaskCommon::getMainTask, MainTaskType.NON_MAIN.getCode()));
    }

    /**
     * 根据任务id，更新任务状态
     * @param id
     * @param status
     * @return
     */
    @Override
    public Boolean updateStatus(Long id, String status) {
        return baseMapper.update(new LambdaUpdateWrapper<PatrolSubtaskCommon>()
        .eq(PatrolSubtaskCommon::getId, id).set(PatrolSubtaskCommon::getStatus, status)) > 0;
    }

    /**
     * 根据任务id和状态查询、主任务标识查询任务数量
     * @param taskId
     * @param status
     * @param mainTask
     * @return
     */
    @Override
    public Long queryCountByStatusAndTaskIdAndMainTask(Long taskId, String status, String mainTask) {
        return baseMapper.selectCount(new LambdaQueryWrapper<PatrolSubtaskCommon>()
            .eq(PatrolSubtaskCommon::getTaskId, taskId)
            .eq(PatrolSubtaskCommon::getStatus, status)
            .eq(PatrolSubtaskCommon::getMainTask, mainTask));
    }

    /**
     * 判断所有非主子任务是否已经完成，如果状态未完成个数 > 1，则更新主子任务状态为过期
     * 且查询未完成任务更新状态为过期
     * @param id
     * @return
     */
    @Override
    public Boolean queryUnFinishTaskUpdateStatusIsExpired(Long id) {
        PatrolSubtaskCommon subtask = baseMapper.selectOne(new LambdaQueryWrapper<PatrolSubtaskCommon>()
            .eq(PatrolSubtaskCommon::getId, id), false);
        if (ObjUtil.isNull(subtask)) {
            throw new TaskException("未找到该任务");
        }
        // 更新未完成子任务状态为过期，失败则抛出异常
        if (!TaskFinishStatus.FINISH.getCode().equals(subtask.getStatus())) {
            baseMapper.update(new LambdaUpdateWrapper<PatrolSubtaskCommon>()
                .ne(PatrolSubtaskCommon::getStatus, TaskFinishStatus.FINISH.getCode())
                .eq(PatrolSubtaskCommon::getId, id)
                .set(PatrolSubtaskCommon::getExpiredStatus, ExpiredStatus.IS_EXPIRED.getCode()));
        }
        return true;
    }

    @Override
    public Boolean queryUnFinishTaskUpdateMainStatusIsExpired(Long id) {
        // 通过主任务id查询所有未完成子任务个数
        Long unFinishedSubTaskCount = baseMapper.selectCount(new LambdaQueryWrapper<PatrolSubtaskCommon>()
            .eq(PatrolSubtaskCommon::getTaskId, id)
            .eq(PatrolSubtaskCommon::getMainTask, MainTaskType.NON_MAIN.getCode())
            .ne(PatrolSubtaskCommon::getStatus, TaskFinishStatus.FINISH.getCode()));
        Long subTaskCount = baseMapper.selectCount(new LambdaQueryWrapper<PatrolSubtaskCommon>()
            .eq(PatrolSubtaskCommon::getTaskId, id)
            .eq(PatrolSubtaskCommon::getMainTask, MainTaskType.NON_MAIN.getCode()));
        // 如果任务数大于1，则更新主任务状态为过期
        if (unFinishedSubTaskCount > 0 && subTaskCount >0) {
            baseMapper.update(new LambdaUpdateWrapper<PatrolSubtaskCommon>()
                .eq(PatrolSubtaskCommon::getTaskId, id)
                .eq(PatrolSubtaskCommon::getMainTask, MainTaskType.MAIN.getCode())
                .set(PatrolSubtaskCommon::getExpiredStatus, ExpiredStatus.IS_EXPIRED.getCode()));
            return true;
        }
        return false;
    }

    /**
     * 根据cycleTaskId，当前时间更新过期任务
     * @param cycleTaskId
     * @param currentDate
     * @return
     */
    @Override
    public Boolean checkAndUpdateExpiredStatus(Long cycleTaskId, String currentDate) {
        return baseMapper.update(new LambdaUpdateWrapper<PatrolSubtaskCommon>()
            .eq(PatrolSubtaskCommon::getCycleTaskId, cycleTaskId)
            .eq(PatrolSubtaskCommon::getExpiredStatus, ExpiredStatus.NOT_EXPIRED.getCode())
            .ne(PatrolSubtaskCommon::getStatus, TaskFinishStatus.FINISH.getCode())
            .eq(PatrolSubtaskCommon::getExecuteDateEnd, currentDate)
            .set(PatrolSubtaskCommon::getExpiredStatus, ExpiredStatus.ABOUT_TO_EXPIRE.getCode())) > 0;
    }
    private RemoteMessageBo createRemoteMessageBo(Executors executor, PatrolExecutors patrolExecutor) {
        RemoteMessageBo messageBo = new RemoteMessageBo();
        messageBo.setRecordId(executor.getExecutor());
        messageBo.setStoreId(patrolExecutor.getStoreId());
        return messageBo;
    }
    /**
     * 批量更新
     * @param list
     * @return
     */
    @Override
    public Boolean updateBatchById(List<PatrolSubtaskCommon> list) {
        return baseMapper.updateBatchById(list);
    }

    /**
     * 删除巡店管理任务  删除所有子任务、定时任务
     * @param id
     * @return
     */
    @Override
    @GlobalTransactional
    public Boolean deleteWithId(Long id) {
        // 通过任务ID查找taskId
        PatrolSubtaskCommon patrolSubtaskCommon = baseMapper.selectById(id);
        if (ObjUtil.isNull(patrolSubtaskCommon)) {
            throw new ServiceException("任务已删除", HttpStatus.MOVED_PERM);
        }
        // 判断是否是租户管理员，是的话，可删除所有主任务，否的话只能删除自己发布的主任务
        if (!LoginHelper.isSuperAdmin()
            && !LoginHelper.isTenantAdmin()
            && !Objects.equals(LoginHelper.getUserId(), patrolSubtaskCommon.getCreator())) {
            throw new ServiceException("无权限删除", HttpStatus.UNAUTHORIZED);
        }
        PatrolTask patrolTask = patrolTaskMapper.selectById(patrolSubtaskCommon.getTaskId());
        if(deleteLogic(patrolSubtaskCommon, patrolTask)) {
            return true;
        }
        throw new TaskException("删除任务失败");
    }

    /**
     * 通过子任务ID 更新状态、开始时间、结束时间
     * @param id
     * @param status
     * @param startTime
     * @param endTime
     * @return
     */
    @Override
    @GlobalTransactional
    public Boolean updateStatusAndTimeById(Long id, String status, Long startTime, Long endTime) {
        if (ObjUtil.isNotNull(startTime)
            && ObjUtil.isNotNull(endTime)
            || ObjUtil.isNull(id)) {
            throw new ServiceException("参数非法", HttpStatus.BAD_REQUEST);
        }
        PatrolSubtaskCommon patrolSubtaskCommon = baseMapper.selectById(id);
        if (ObjUtil.isNull(patrolSubtaskCommon)) {
            throw new ServiceException("未找到该任务", HttpStatus.MOVED_PERM);
        }
        patrolSubtaskCommon.setStatus(status);
        baseMapper.updateById(patrolSubtaskCommon);
        PatrolSubtaskCommon patrolMainSubtaskCommon = baseMapper.selectOne(new LambdaUpdateWrapper<PatrolSubtaskCommon>()
            .eq(PatrolSubtaskCommon::getTaskId, patrolSubtaskCommon.getTaskId())
            .eq(PatrolSubtaskCommon::getMainTask, MainTaskType.MAIN.getCode()));
        // 巡店任务开始执行
        if (ObjUtil.isNotNull(startTime)
            && ObjUtil.isNull(endTime)) {
            // 判断主任务完成状态，如果是第一个开始执行的子任务，则更新主任务状态为执行中，否则不处理
            if (ObjUtil.isNotNull(patrolMainSubtaskCommon)
                && TaskFinishStatus.TODO.getCode().equals(patrolMainSubtaskCommon.getStatus())) {
                patrolMainSubtaskCommon.setStatus(TaskFinishStatus.PROCESSING.getCode());
                if (baseMapper.updateById(patrolMainSubtaskCommon) > 0) {
                    return true;
                } else {
                    throw new PatrolException("更新主任务过期状态失败");
                }
            }
        }
        // 巡店任务执行结束
        if (ObjUtil.isNull(startTime)
            && ObjUtil.isNotNull(endTime)) {
            // 判断主任务完成状态，
            // 如果是任务的最后一天，查找是否含有未完成的子任务，
            // 如果没有则更新主任务状态为已完成，否则不处理，保持状态为执行中
            String dateStr = DateUtils.parseDateToStr("yyyy-MM-dd", new Date());
            if (dateStr.equals(patrolMainSubtaskCommon.getExecuteDateEnd())) {
                Long unFinishedSubTaskCount = baseMapper.selectCount(new LambdaQueryWrapper<PatrolSubtaskCommon>()
                    .eq(PatrolSubtaskCommon::getTaskId, patrolMainSubtaskCommon.getTaskId())
                    .eq(PatrolSubtaskCommon::getMainTask, MainTaskType.NON_MAIN.getCode())
                    .ne(PatrolSubtaskCommon::getStatus, TaskFinishStatus.FINISH.getCode()));
                if (unFinishedSubTaskCount <= 0) {
                    patrolMainSubtaskCommon.setStatus(TaskFinishStatus.FINISH.getCode());
                    if (baseMapper.updateById(patrolMainSubtaskCommon) > 0) {
                        return true;
                    } else {
                        throw new PatrolException("更新主任务过期状态失败");
                    }
                }
            }
        }
        return true;
    }

    /**
     * 删除门店关联的任务
     * @param storeId
     * @return
     */
    @Override
    public Boolean deleteTaskWithStoreId(Long storeId) {
        if (ObjUtil.isNull(storeId)) {
            return true;
        }
        return baseMapper.delete(new LambdaUpdateWrapper<PatrolSubtaskCommon>()
            .eq(PatrolSubtaskCommon::getMainTask, MainTaskType.NON_MAIN.getCode())
            .eq(PatrolSubtaskCommon::getStoreId, storeId)
            .or(true, wrapper -> wrapper.apply("JSON_LENGTH(store_ids) = 1")
                .apply("CAST(JSON_UNQUOTE(JSON_EXTRACT(store_ids, '$[0]')) AS UNSIGNED) = " + storeId)
                    .eq(PatrolSubtaskCommon::getMainTask, MainTaskType.MAIN.getCode()))) > 0;
    }
}
